#include "GameState.h"
#include "PhysicalObject.h"
#include "SFML/OpenGL.hpp"
#include <SFML/Audio.hpp>

#include <iostream>
using namespace std;
using namespace sf;

GameState::GameState() : m_world(b2Vec2(0.0f, -10.0f)),
						 m_accumulator(0.0),
						 m_currentTime(0.0),
						 m_nextId(1),
						 m_player(NULL)
{
	glOrtho(-20, 20, -15, 15, -100, 100);
	

	glEnable(GL_BLEND);
	glEnable(GL_TEXTURE_2D);
	glEnable( GL_POINT_SMOOTH );
	glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glClearColor(0.4f, 0.9f, 1.0f, 1.0f);

	m_world.SetContactListener(this);

  m_currentLevel = 1;
  m_maxLevels = 6;
   m_levelCompleted = false;
	

}


GameState::~GameState()
{
}


void GameState::addObject(GameObject* object){

	if(object->hasProperty("physical")){
		PhysicalObject *temp = static_cast<PhysicalObject*>(object);
		temp->getBodyDef()->position = temp->getPosition();
		b2Body *body = m_world.CreateBody(temp->getBodyDef());

		for(int i = 0; i < temp->getFixtureDefCount(); i++){
			b2FixtureDef *def = temp->getFixtureDef(i);
			body->CreateFixture(def);
		}

		body->SetUserData(temp);
		temp->setBody(body);
	}

	object->setId(m_nextId);
	m_nextId++;
	m_objects.push_back(object);
}


void GameState::update(double dt){

   
	 if ( dt > 0.25 )
        dt = 0.25;	  // note: max frame time to avoid spiral of death
   
    
    //const double alpha = m_accumulator / dt;

	list<GameObject*>::iterator it = m_objects.begin();

	while(it!=m_objects.end()){
		GameObject *object = (*it);
		if(object->isFirstUpdate()){
			object->firstUpdate();
			object->setFirstUpdate(false);
		}
		object->update(dt);
		
		if(!object->isAlive()){
			if(object->hasProperty("physical")){
				PhysicalObject *physObject = static_cast<PhysicalObject*>(object);
				m_world.DestroyBody(physObject->getBody());
			}
			delete object;
			it = m_objects.erase(it);
		}else{
			++it;
		}
	}

	m_accumulator += dt;

	
    while ( m_accumulator >= TIMESTEP ){
        m_world.Step(TIMESTEP, 13, 8); 
        m_accumulator -= TIMESTEP;
	
    }


}


void GameState::draw(){
	
	glClear(GL_COLOR_BUFFER_BIT);
	list<GameObject*>::iterator it;

	for(it = m_objects.begin(); it!=m_objects.end(); ++it){
		GameObject *object = (*it);
		object->draw();
	}
}

JumpController * GameState::getJumpController()
{
	for(list<GameObject*>::iterator it = m_objects.begin(); it!=m_objects.end(); ++it){
		GameObject *object = (*it);
    if (object->hasProperty("jumpcontroller"))
		   return (JumpController *) object;
	}
  return 0;
}

Floor * GameState::getFloor()
{
	for(list<GameObject*>::iterator it = m_objects.begin(); it!=m_objects.end(); ++it){
		GameObject *object = (*it);
    if (object->hasProperty("floor"))
		   return (Floor *) object;
	}
  return 0;
}

void GameState::BeginContact(b2Contact* contact){
	PhysicalObject *objectA = (PhysicalObject*)contact->GetFixtureA()->GetBody()->GetUserData();
	objectA->beginContact(contact);

	PhysicalObject *objectB = (PhysicalObject*)contact->GetFixtureB()->GetBody()->GetUserData();
	objectB->beginContact(contact);
}


void GameState::EndContact(b2Contact* contact){
	PhysicalObject *objectA = (PhysicalObject*)contact->GetFixtureA()->GetBody()->GetUserData();
	objectA->endContact(contact);

	PhysicalObject *objectB = (PhysicalObject*)contact->GetFixtureB()->GetBody()->GetUserData();
	objectB->endContact(contact);
}


void GameState::PreSolve(b2Contact* contact, const b2Manifold* oldManifold){
	PhysicalObject *objectA = (PhysicalObject*)contact->GetFixtureA()->GetBody()->GetUserData();
	objectA->PreSolve(contact, oldManifold);

	PhysicalObject *objectB = (PhysicalObject*)contact->GetFixtureB()->GetBody()->GetUserData();
	objectB->PreSolve(contact, oldManifold);
}


void GameState::PostSolve(b2Contact* contact, const b2ContactImpulse* impulse){
	PhysicalObject *objectA = (PhysicalObject*)contact->GetFixtureA()->GetBody()->GetUserData();
	objectA->PostSolve(contact, impulse);

	PhysicalObject *objectB = (PhysicalObject*)contact->GetFixtureB()->GetBody()->GetUserData();
	objectB->PostSolve(contact, impulse);
}
